package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itzhanshen.sys.feign.SysUserFeign;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendanceService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NCException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.CurrentUserHolder;
import com.nineclock.common.utils.DateTimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class AttendanceServiceImpl implements AttendanceService {
    @Autowired
    AttendGroupMapper attendGroupMapper;
    @Autowired
    SysUserFeign sysUserFeign;
    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    /**
     * 获取考勤组列表
     *
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> getAttendGroupByUserId(Integer page, Integer pageSize) {
        // 企业Id,根据企业ID获取考勤组,如果有则进行分页展示,如果没有,则新建一个默认的考勤组,对企业进行关联
        Long companyId = CurrentUserHolder.get().getCompanyId();
        LambdaQueryWrapper<AttendGroup> attendGroupWrapper = new LambdaQueryWrapper<>();
        attendGroupWrapper.eq(AttendGroup::getCompanyId, companyId);
        Integer count = attendGroupMapper.selectCount(attendGroupWrapper);
        if (count == 0) {
            // 没有考勤组,添加一个默认的考勤组并分配部门
            AttendGroup attendGroup = buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);
            // 查询企业并分配相关考勤组
            List<Long> departmentIds = sysUserFeign.findDepartmentByCompanyId().getData();
            for (Long departmentId : departmentIds) {
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
                attendGroupPart.setObjectId(departmentId);
                attendGroupPartMapper.insert(attendGroupPart);
            }
        }
        // 分页查询考勤组
        Page<AttendGroup> pages = new Page<>(page, pageSize);
        attendGroupMapper.selectPage(pages, attendGroupWrapper);
        List<AttendGroup> records = pages.getRecords();
        List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);
        // 遍历考勤组列表，获取企业考勤组中参与者数量 ---
        // 区分是部门, 还是员工 , 如果是部门要获取部门下的员工数量
        for (AttendGroupDTO attendGroupDTO : attendGroupDTOS) {
            Long id = attendGroupDTO.getId();
            // 封装查询条件,获取参与人数量
            LambdaQueryWrapper<AttendGroupPart> groupPartWrapper = new LambdaQueryWrapper<>();
            groupPartWrapper.eq(AttendGroupPart::getAttendGroupId, id);
            groupPartWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
            List<AttendGroupPart> attendGroupParts = attendGroupPartMapper.selectList(groupPartWrapper);
            // 获取参与者是部门的集合
            List<Long> departmentIds = new ArrayList<>();
            for (AttendGroupPart attendGroupPart : attendGroupParts) {
                if (attendGroupPart.getObjectType() == 1) {
                    departmentIds.add(attendGroupPart.getObjectId());
                }
            }
            // 获取参与者是用户的集合
            List<Long> userIds = new ArrayList<>();
            for (AttendGroupPart attendGroupPart : attendGroupParts) {
                if (attendGroupPart.getObjectType() == 2) {
                    userIds.add(attendGroupPart.getObjectId());
                }
            }
            // 根据部门id集合获取所对应的所有员工
            Integer departUserCount = sysUserFeign.findAttendAndCompanyUserCount(departmentIds).getData();
            // 组装参数,计算部门和用户总数量
            Integer countResult = departUserCount + userIds.size();
            attendGroupDTO.setMemberNum(countResult);
        }
        return new PageResult<>(pages.getTotal(), pages.getPages(), attendGroupDTOS);
    }

    /**
     * 添加考勤组
     * @param attendGroupDTO
     */
    @Override
    public void attendGroup(AttendGroupDTO attendGroupDTO) {
        // 参数校验
        if (attendGroupDTO == null) {
            throw new NCException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        // 组装参数--插入考勤组
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyUserId());
        //组装工作日,以逗号隔开
        if (attendGroupDTO.getWorkdays() != null) {
            attendGroup.setWorkdays(StrUtil.join(",", attendGroupDTO.getWorkdays().toArray()));
        }
        // 设置必须/不用打卡的日期,用,进行分割
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        List<String> mustPunchDate = new ArrayList<>();
        List<String> noMustPunchDate = new ArrayList<>();
        for (AttendGroupPCExtraConfigDTO attendGroupPCExtraConfigDTO : extraConfig) {
            String time = attendGroupPCExtraConfigDTO.getSetDate();
            String dateStr = DateTimeUtil.dateToStr(new Date(Long.valueOf(time)), "yyyy-MM-dd");
            if (attendGroupPCExtraConfigDTO.getRequiredAttend() == 1) {
                mustPunchDate.add(dateStr);
            } else {
                noMustPunchDate.add(dateStr);
            }
        }
        // 必须打卡日期集合
        if (mustPunchDate != null) {
            attendGroup.setNecessaryTimeList(StrUtil.join(",", mustPunchDate.toArray()));
        }
        // 不须打卡日期集合
        if (noMustPunchDate != null) {
            attendGroup.setUnnecessaryTimeList(StrUtil.join(",", noMustPunchDate.toArray()));
        }
        // 插入数据库
        attendGroupMapper.insert(attendGroup);
    //    保存关联 用户, 部门到该考勤组
        this.saveAttendGroupPart(attendGroupDTO, attendGroup.getId());
    }
// 保存关联 --用户/部门到该考勤组
    private void saveAttendGroupPart(AttendGroupDTO attendGroupDTO, Long id) {
        // 参与考勤人员
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
        // 判断当前对象是否加入了别的考勤组
        //（要求 : 用户/部门 只能加入一个考勤组，如果设置新考勤组 删除旧的考勤组）
        for (AttendGroupPartDTO participate : participates) {
            LambdaQueryWrapper<AttendGroupPart> groupPartWrapper = new LambdaQueryWrapper<>();
            groupPartWrapper.eq(AttendGroupPart::getAttendGroupId, participate.getObjectId());
            groupPartWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
            groupPartWrapper.eq(AttendGroupPart::getObjectType, participate.getObjectType());
            Integer count = attendGroupPartMapper.selectCount(groupPartWrapper);
            if (count > 0) {
                // 参加了考勤组,删除原来的,并设置新的考勤组
                attendGroupPartMapper.delete(groupPartWrapper);
            }
            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setObjectId(participate.getObjectId());
            attendGroupPart.setObjectType(participate.getObjectType());
            attendGroupPart.setAttendGroupId(id);
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value());
            attendGroupPartMapper.insert(attendGroupPart);
        }
        // 未参与考勤人员
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
        notParticipates.stream().forEach(attendGroupPartDTO -> {
            AttendGroupPart attendGroupPart = new AttendGroupPart();
            attendGroupPart.setObjectId(attendGroupPart.getObjectId());
            attendGroupPart.setObjectType(attendGroupPart.getObjectType());
            attendGroupPart.setAttendGroupId(attendGroupPart.getObjectId());
            attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_NO.value());
            attendGroupPartMapper.insert(attendGroupPart);
        });
    }

    //构建默认的考勤组
    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setAddressRange(500);
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        attendGroup.setUpdateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setUpdateTime(new Date());
        attendGroup.setLat(new BigDecimal("116.37439200000000000000"));//TBD
        attendGroup.setLng(new BigDecimal("40.10492600000000000000"));//TBD
        attendGroup.setAddressName("七北路42号TBD云集中心2号楼3单元3层");
        attendGroup.setAddress("传智播客北京中心TBD校区");
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setOffWorkTime("18:00:00");
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setLateMinutes(30);
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        return attendGroup;
    }

    /**
     * 根据当前登录用户获取考勤组列表
     * @return
     */
    @Override
    public AttendGroupDTO queryAttendGroup() {
        // 获取当前登录用户
        Long userId = CurrentUserHolder.get().getId();
     Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        // 根据系统用户获取考勤参与者对象
        LambdaQueryWrapper<AttendGroupPart> groupWrapper = new LambdaQueryWrapper<>();
        groupWrapper.eq(AttendGroupPart::getObjectId, userId);
        groupWrapper.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());
        groupWrapper.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(groupWrapper);
        if (attendGroupPart == null) {
            // 获取系统用户所在的上级部门Id集合
            List<Long> demIds = sysUserFeign.findDepartmentIdByCompanyUserId(companyUserId).getData();
            if (demIds != null) {
                // 根据系统部门ID集合获取考勤参与对象
                for (Long demId : demIds) {
                    LambdaQueryWrapper<AttendGroupPart> groupWrapper1 = new LambdaQueryWrapper<>();
                    groupWrapper1.eq(AttendGroupPart::getObjectId, demId);
                    groupWrapper1.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());
                    groupWrapper1.eq(AttendGroupPart::getAttendType, AttendEnums.ATTEND_TYPE_YES.value());
                     attendGroupPart = attendGroupPartMapper.selectOne(groupWrapper1);
                    if (attendGroupPart != null) {
                        break;
                    }
                }
            }
        }
        // 获取考勤组
        if (attendGroupPart == null) {
            throw new NCException(ResponseEnum.USER_NOT_MATCH_ATTENDGROUP);
        }
        Long attendGroupId = attendGroupPart.getAttendGroupId();
        AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
        // 组装参数
        if (attendGroup != null) {
            // 设置工作日字段集合
            AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
            attendGroupDTO.setWorkdays(Arrays.asList(attendGroup.getWorkdays().split(",")));
            // 返回数据
            return attendGroupDTO;
        }
        return null;
    }

}
